#include "sys.h"
#include "net.h"
#include "log.h"
#include "thread_pool.h"
#include "platform.h"
#include "cJSON.h"
#include "dial.h"
#include "miss.h"
#include "miss_interface.h"
#include "miss_error.h"

#define RESET_MIN_MAX(min, max) \
    (min = 0);                  \
    (max = 0)

//UDP
static float *Rate_Arr = NULL;
static int Rate_Arr_idx = 0;
static int Total_Bytes = 0;
//http
static float Max_rate, Min_rate;
static int* Valid_bytes_ptr;
static int Valid_bytes_count;
static int Ignore_time, Total_time, Interval_time;

struct down_up_urls {
    int up_count, down_count;
    char** up;
    char** down;
};

static int _get_cur_bytes()
{
    int i = 0;
    int bytes = 0;
    for (i = 0; i < Valid_bytes_count; i++) {
        bytes += Valid_bytes_ptr[i];
    }
    return bytes;
}
static void* _cal_max_min_rate(void* arg)
{
    int i = 0;
    float cur_rate = 0;
    int startTime = 0;
    int prev_bytes, cur_bytes;
    int total_time = Total_time;

    usleep(MSEC2USEC(Ignore_time));
    prev_bytes = _get_cur_bytes();
    total_time -= Ignore_time;
    while ((total_time -= Interval_time) > 0) {
        usleep(MSEC2USEC(Interval_time));
        cur_bytes = _get_cur_bytes();
        cur_rate = (float)(cur_bytes - prev_bytes) * 8 / MSEC2SEC(Interval_time);
        Max_rate = MAX_VAL(cur_rate, Max_rate);
        Min_rate = Min_rate ? MIN_VAL(cur_rate, Min_rate) : cur_rate;
        prev_bytes = cur_bytes;
    }
}
static void _free_down_up_urls(struct down_up_urls* urls, int flg_down)
{
    int i = 0;

    if (flg_down) {
        for (i = 0; i < urls->down_count; i++) {
            free(urls->down[i]);
        }
        free(urls->down);
    } else {
        for (i = 0; i < urls->up_count; i++) {
            free(urls->up[i]);
        }
        free(urls->up);
    }
}
static void _get_urls(struct down_up_urls* du_urls, char* urls, int flg_down)
{
    int count = 0, i = 0;
    char* delim = ",", *saveptr;
    char *ptr, *tmp_urls;

    if (strlen(urls) == 0)
        return;

    count++;
    tmp_urls = strdup(urls);
    ptr = tmp_urls;
    while ((ptr = strchr(ptr, ','))) {
        count++;
        ptr++;
    }

    if (flg_down) {
        du_urls->down_count = count;
        du_urls->down = calloc(count, sizeof(char*));
        ptr = strtok_r(tmp_urls, delim, &saveptr);
        du_urls->down[i++] = strdup(ptr);
        while (ptr = strtok_r(NULL, delim, &saveptr)) {
            du_urls->down[i++] = strdup(ptr);
        }
    } else {
        du_urls->up_count = count;
        du_urls->up = calloc(count, sizeof(char*));
        ptr = strtok_r(tmp_urls, delim, &saveptr);
        du_urls->up[i++] = strdup(ptr);
        while (ptr = strtok_r(NULL, delim, &saveptr)) {
            du_urls->up[i++] = strdup(ptr);
        }
    }
    free(tmp_urls);
}
static void _get_http_hosts(char* urls, char* addrs)
{
    char* ptr;
    char* delim = ",", *saveptr;
    char host[32] = { 0 };

    if (strlen(urls) == 0)
        return;

    ptr = strtok_r(urls, delim, &saveptr);
    http_get_host(ptr, host);
    strcat(addrs, host);
    strcat(addrs, ",");

    while ((ptr = strtok_r(NULL, delim, &saveptr))) {
        http_get_host(ptr, host);
        strcat(addrs, host);
        strcat(addrs, ",");
    }
}

static int accept_process_data(PProcessResult pData, IN void* arg)
{
    // log_trace("udpspeed: rate = %.2f Mbps, sendRate = %.2f, lost = %.2f", pData->dRate, pData->dSendRate, pData->dLost);
    if(pData->dRate < 0){
        return 0;
    }
    Rate_Arr[Rate_Arr_idx++] = pData->dRate * 1000 * 1000;
    Total_Bytes += (pData->dRate * 1000 * 1000 / 8);
    return 0;
}
static int rate_compare(void *a, void *b){
    float *aa = (float *)a;
    float *bb = (float *)b;

    if(*aa > *bb)return 1;
    if(*aa == *bb) return 0;
    if(*aa < *bb) return -1;
}
static float cal_avg(int s_idx, int e_idx, float *arr){
    int i =0;
    float sum = 0;

    log_trace("s_idx:%d, e_idx:%d", s_idx, e_idx);

    if(e_idx == 0)
        return 0;

    for (i = s_idx; i < e_idx; ++i)
    {
        sum += arr[i];
    }

    return sum / (e_idx - s_idx);
}
static void _show_rate_detail(float *rate_arr, int count){
    int i = 0;

    for ( i = 0; i < count; ++i)
    {
        log_trace("rate:%.2f, idx:%d", rate_arr[i], i);
    }
}
static int _do_udp_download(cJSON* cdup_down, cJSON* root)
{
    int ret = 0, tmp_idx = 0;
    float avg_speed = 0;
    char tmp_str[32], addrs[512];
    int tcpPort, udpPort, down_time;

    cJSON* c_ip = cJSON_GetObjectItem(cdup_down, "ip");
    cJSON* cdown_time = cJSON_GetObjectItem(cdup_down, "timeout");
    cJSON* cdown_tcpPort = cJSON_GetObjectItem(cdup_down, "tcpPort");
    cJSON* cdown_udpPort = cJSON_GetObjectItem(cdup_down, "udpPort");
    cJSON* cdown_discardPercent = cJSON_GetObjectItem(cdup_down, "discardPercent");
    // cJSON* cthreads = cJSON_GetObjectItem(cdup_down, "threads");

    if(!c_ip || !cdown_time || !cdown_tcpPort || !cdown_udpPort || !cdown_discardPercent)
        return -1;

    if (strlen(c_ip->valuestring) == 0)
        return -1;

    tcpPort = cdown_tcpPort->valueint;
    udpPort = cdown_udpPort->valueint;
    down_time = cdown_time->valueint;

    Rate_Arr_idx = 0;
    Total_Bytes = 0;
    Rate_Arr = calloc(down_time, sizeof(float));
    // log_trace("ip:%s, tcpPort:%d, udpPort:%d, bdcode_val:%d, timeout:%d", c_ip->valuestring, tcpPort, udpPort, ((int)Mbps(commReqParam.bdcode_val)), downTactics->timeout );
    ret = miss_test_start(c_ip->valuestring, tcpPort, udpPort, ((int)Mbps(commReqParam.bdcode_val)), down_time, 1, 1000, 2, accept_process_data);
    if(ret < 0){
        log_error("specify udp download miss_test_start ret:%d", ret);
        cJSON_AddStringToObject(root, "downMinSpeed", "0");
        cJSON_AddStringToObject(root, "downMaxSpeed", "0");
        cJSON_AddStringToObject(root, "downAvgSpeed", "0");
        cJSON_AddNumberToObject(root, "downActualDuration", 0);
        cJSON_AddNumberToObject(root, "downActualSize", 0);
        return -1;
    }else{
        qsort(Rate_Arr, Rate_Arr_idx, sizeof(float), rate_compare);
        _show_rate_detail(Rate_Arr, Rate_Arr_idx);
        tmp_idx = Rate_Arr_idx * (cdown_discardPercent->valueint / 100.0);
        avg_speed = cal_avg(tmp_idx, Rate_Arr_idx, Rate_Arr);

        strcpy(tmp_str, "0");
        cJSON_AddStringToObject(root, "avgDelayTime", tmp_str);

        sprintf(tmp_str, "%.0f", KBps(Rate_Arr[tmp_idx] / 8));
        cJSON_AddStringToObject(root, "downMinSpeed", tmp_str);

        if(Rate_Arr_idx)
            sprintf(tmp_str, "%.0f", KBps(Rate_Arr[Rate_Arr_idx - 1] / 8));
        else
            sprintf(tmp_str, "%.0f", KBps(Rate_Arr[0] / 8));
        cJSON_AddStringToObject(root, "downMaxSpeed", tmp_str);

        sprintf(tmp_str, "%.0f", KBps(avg_speed / 8));
        cJSON_AddStringToObject(root, "downAvgSpeed", tmp_str);
        cJSON_AddNumberToObject(root, "downActualDuration", down_time * 1000);
        cJSON_AddNumberToObject(root, "downActualSize", Total_Bytes);

        free(Rate_Arr);

        if( avg_speed == 0 ){
            return -1;
        }else{
            return 1;
        }
    }
    return -1;
}
static void _do_http_download(cJSON* chttp_down, cJSON* root)
{
    char tmp_str[32], addrs[512];
    dial_arg_t dial_arg = { 0 };
    dial_result_t* dial_result = NULL;
    http_result_t* httpdown_result = NULL;
    struct down_up_urls du_urls;

    cJSON* curls = cJSON_GetObjectItem(chttp_down, "urls");
    cJSON* cdown_time = cJSON_GetObjectItem(chttp_down, "downTime");
    cJSON* cignoreTime = cJSON_GetObjectItem(chttp_down, "ignoreTime");
    cJSON* cthreads = cJSON_GetObjectItem(chttp_down, "threads");

    if (strlen(curls->valuestring) == 0)
        return;

    _get_urls(&du_urls, curls->valuestring, 1);

    RESET_MIN_MAX(Min_rate, Max_rate);
    dial_arg.in.http_arg.uris = du_urls.down;
    dial_arg.in.http_arg.uris_count = du_urls.down_count;
    dial_arg.in.http_arg.threads = cthreads->valueint;
    Valid_bytes_count = dial_arg.in.http_arg.threads;
    Valid_bytes_ptr = calloc(Valid_bytes_count, sizeof(int));
    dial_arg.in.http_arg.valid_bytes_ptr = Valid_bytes_ptr;
    Total_time = dial_arg.in.http_arg.duration = SEC2MSEC(cdown_time->valueint);
    Interval_time = dial_arg.in.http_arg.interval = SEC2MSEC(1);
    Ignore_time = dial_arg.in.http_arg.ignore_duration = SEC2MSEC(cignoreTime->valueint);

    pthread_t thid;
    pthread_create(&thid, NULL, _cal_max_min_rate, NULL);
    dial_result = (dial_result_t*)dial_http_download(&dial_arg);
    dial_result->out.http_result.min_rate = Min_rate;
    dial_result->out.http_result.max_rate = Max_rate;
    http_result_print(&dial_result->out.http_result);

    pthread_join(thid, NULL);

    sprintf(tmp_str, "%.0f", dial_result->out.http_result.latency);
    cJSON_AddStringToObject(root, "avgDelayTime", tmp_str);
    sprintf(tmp_str, "%.0f", KBps(dial_result->out.http_result.min_rate / 8));
    cJSON_AddStringToObject(root, "downMinSpeed", tmp_str);
    sprintf(tmp_str, "%.0f", KBps(dial_result->out.http_result.max_rate / 8));
    cJSON_AddStringToObject(root, "downMaxSpeed", tmp_str);
    sprintf(tmp_str, "%.0f", KBps(dial_result->out.http_result.rate / 8));
    cJSON_AddStringToObject(root, "downAvgSpeed", tmp_str);
    cJSON_AddNumberToObject(root, "downActualDuration", dial_result->out.http_result.total_time);
    cJSON_AddNumberToObject(root, "downActualSize", dial_result->out.http_result.total_bytes);
    free(dial_result);
    free(Valid_bytes_ptr);
    _free_down_up_urls(&du_urls, 1);
}

static void _do_http_upload(cJSON* chttp_up, cJSON* root)
{
    char tmp_str[32], addrs[512];
    dial_arg_t dial_arg = { 0 };
    dial_result_t* dial_result = NULL;
    http_result_t* httpup_result = NULL;
    struct down_up_urls du_urls;

    cJSON* curls = cJSON_GetObjectItem(chttp_up, "urls");
    cJSON* cup_time = cJSON_GetObjectItem(chttp_up, "upTime");
    cJSON* cignoreTime = cJSON_GetObjectItem(chttp_up, "ignoreTime");
    cJSON* cthreads = cJSON_GetObjectItem(chttp_up, "threads");

    if (strlen(curls->valuestring) == 0)
        return;

    _get_urls(&du_urls, curls->valuestring, 0);

    RESET_MIN_MAX(Min_rate, Max_rate);
    dial_arg.in.http_arg.uris = du_urls.up;
    dial_arg.in.http_arg.uris_count = du_urls.up_count;
    dial_arg.in.http_arg.threads = cthreads->valueint;
    Valid_bytes_count = dial_arg.in.http_arg.threads;
    Valid_bytes_ptr = calloc(Valid_bytes_count, sizeof(int));
    dial_arg.in.http_arg.valid_bytes_ptr = Valid_bytes_ptr;
    Total_time = dial_arg.in.http_arg.duration = SEC2MSEC(cup_time->valueint);
    Interval_time = dial_arg.in.http_arg.interval = SEC2MSEC(1);
    Ignore_time = dial_arg.in.http_arg.ignore_duration = SEC2MSEC(cignoreTime->valueint);

    pthread_t thid;
    pthread_create(&thid, NULL, _cal_max_min_rate, NULL);
    dial_result = (dial_result_t*)dial_http_upload(&dial_arg);
    dial_result->out.http_result.min_rate = Min_rate;
    dial_result->out.http_result.max_rate = Max_rate;
    http_result_print(&dial_result->out.http_result);

    pthread_join(thid, NULL);

    sprintf(tmp_str, "%.0f", KBps(dial_result->out.http_result.min_rate / 8));
    cJSON_AddStringToObject(root, "upMinSpeed", tmp_str);
    sprintf(tmp_str, "%.0f", KBps(dial_result->out.http_result.max_rate / 8));
    cJSON_AddStringToObject(root, "upMaxSpeed", tmp_str);
    sprintf(tmp_str, "%.0f", KBps(dial_result->out.http_result.rate / 8));
    cJSON_AddStringToObject(root, "upAvgSpeed", tmp_str);
    cJSON_AddNumberToObject(root, "upActualDuration", dial_result->out.http_result.total_time);
    cJSON_AddNumberToObject(root, "upActualSize", dial_result->out.http_result.total_bytes);
    free(dial_result);
    free(Valid_bytes_ptr);
    _free_down_up_urls(&du_urls, 0);
}
static void _do_specify_http_speed(cJSON* speedTactics, cJSON* cjson_ret)
{
    char addrs[1024 * 2] = {0};
    cJSON* root = cJSON_CreateObject();
    // cJSON* chttp_down = cJSON_GetObjectItem(speedTactics, "httpDownloadTactics");
    cJSON* chttp_up = cJSON_GetObjectItem(speedTactics, "httpUploadTactics");
    cJSON* cudp_down = cJSON_GetObjectItem(speedTactics, "udpdownTactics");

    // cJSON* down_curls = cJSON_GetObjectItem(chttp_down, "urls");
    cJSON* up_curls = cJSON_GetObjectItem(chttp_up, "urls");
    cJSON* udpdown_ip = cJSON_GetObjectItem(cudp_down, "ip");

    SPEEDTEST_LOCK();

    _get_http_hosts(up_curls->valuestring, addrs);
    strcat(addrs, udpdown_ip->valuestring);
    cJSON_AddStringToObject(root, "address", addrs);

    // log_trace("do specify httpDownloadTactics task");
    // _do_http_download(chttp_down, root);
    log_trace("do specify udpDownloadTactics task");
    _do_udp_download(cudp_down, root);

    log_trace("do specify httpUploadTactics task");
    _do_http_upload(chttp_up, root);

    cJSON_AddItemToObject(cjson_ret, "testIndexData", root);
    
    SPEEDTEST_UNLOCK();
}

static void _do_specify_ping(cJSON* tactics, cJSON* cjson_ret)
{
    int i;
    char tmp_str[32], *detail_str;
    dial_arg_t dial_arg = { 0 };
    dial_result_t* dial_result = NULL;
    ping_result_t* ping_result = NULL;
    cJSON* root;

    root = cJSON_CreateObject();

    cJSON* type = cJSON_GetObjectItem(tactics, "type");
    cJSON* chost = cJSON_GetObjectItem(tactics, "host");
    cJSON* csize = cJSON_GetObjectItem(tactics, "size");
    cJSON* ctimes = cJSON_GetObjectItem(tactics, "times");
    cJSON* ctimeout = cJSON_GetObjectItem(tactics, "timeout");
    dial_arg.in.ping_arg.ip = wd_ipaddr(chost->valuestring);
    dial_arg.in.ping_arg.blocksize = csize->valueint;
    dial_arg.in.ping_arg.counts = ctimes->valueint;
    dial_arg.in.ping_arg.timeout = ctimeout->valueint;
    dial_arg.in.ping_arg.detail = calloc(ctimes->valueint, sizeof(ping_detail_t));
    dial_result = (dial_result_t*)dial_ping(&dial_arg);
    ping_result_print(&dial_result->out.ping_result);

    ping_result = &dial_result->out.ping_result;
    cJSON_AddStringToObject(root, "host", chost->valuestring);

    sprintf(tmp_str, "%.2f", ping_result->lost_percent);
    cJSON_AddStringToObject(root, "loss", tmp_str);

    sprintf(tmp_str, "%.2f", ping_result->jitter);
    cJSON_AddStringToObject(root, "jitter", tmp_str);

    sprintf(tmp_str, "%.2f", ping_result->latency);
    cJSON_AddStringToObject(root, "avgDelayTime", tmp_str);

    sprintf(tmp_str, "%.2f", ping_result->max_latency);
    cJSON_AddStringToObject(root, "maxDelayTime", tmp_str);

    sprintf(tmp_str, "%.2f", ping_result->min_latency);
    cJSON_AddStringToObject(root, "minDelayTime", tmp_str);

    cJSON_AddNumberToObject(root, "pingByte", csize->valueint);
    cJSON_AddNumberToObject(root, "packetSend", ping_result->snd_count);
    cJSON_AddNumberToObject(root, "packetRecept", ping_result->rcv_count);

    cJSON_AddNumberToObject(root, "packetLoss", (ping_result->snd_count - ping_result->rcv_count));
    cJSON_AddNumberToObject(root, "errCode", dial_result->err);


    detail_str = calloc(ctimes->valueint, 32);
    for (i = 0; i < ctimes->valueint; i++) {
        sprintf(tmp_str, "%.2f,%d|", dial_arg.in.ping_arg.detail[i].latency,
            dial_arg.in.ping_arg.detail[i].ttl);
        strcat(detail_str, tmp_str);
    }
    cJSON_AddStringToObject(root, "detail", detail_str);
    cJSON_AddItemToObject(cjson_ret, "testIndexData", root);

    free(dial_arg.in.ping_arg.detail);
    free(detail_str);
    free(dial_result);
}
static void _do_specify_traceroute(cJSON* tactics, cJSON* cjson_ret)
{
    int i = 0, n = 0, m = 0;
    char *ip_list_str = NULL, *latency_list_str = NULL;
    dial_arg_t dial_arg = { 0 };
    dial_result_t* dial_result = NULL;
    tr_result_t* tr_result = NULL;


    cJSON* toAddress = cJSON_GetObjectItem(tactics, "toAddress");
    cJSON* size = cJSON_GetObjectItem(tactics, "size");
    cJSON* maxNum = cJSON_GetObjectItem(tactics, "maxNum");
    cJSON* timeout = cJSON_GetObjectItem(tactics, "timeout");
    cJSON* type = cJSON_GetObjectItem(tactics, "type");

    dial_arg.in.tr_arg.ip = wd_ipaddr(toAddress->valuestring);
    dial_arg.in.tr_arg.port = port_random(0);
    dial_arg.in.tr_arg.max_hop = maxNum->valueint;
    dial_arg.in.tr_arg.timeout = timeout->valueint;
    dial_arg.in.tr_arg.blocksize = size->valueint;
    dial_arg.in.tr_arg.opt = strcmp(type->valuestring, "udp") == 0 ? OPT_PRO_UDP : OPT_PRO_ICMP;
    dial_result = (dial_result_t*)dial_traceroute(&dial_arg);
    tr_result_print(&dial_result->out.tr_result);
    tr_result = &dial_result->out.tr_result;

    cJSON* root;
    root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "toAddress", toAddress->valuestring);
    cJSON_AddNumberToObject(root, "hopNum", tr_result->ret[tr_result->count - 1].ttl);

    ip_list_str = calloc(tr_result->count, 16);
    //因为需要三组延迟时间，所以分配64
    latency_list_str = calloc(tr_result->count, 64);

    for (i = 0; i < tr_result->count; i++) {
        n += sprintf(ip_list_str + n, "%s,", inet_ntoa(*((struct in_addr*)&tr_result->ret[i].ip)));
        m += sprintf(latency_list_str + m, "%.2f,%.2f,%.2f|", tr_result->ret[i].latency[0],
            tr_result->ret[i].latency[1],
            tr_result->ret[i].latency[2]);
    }
    cJSON_AddStringToObject(root, "traceIP", ip_list_str);
    cJSON_AddStringToObject(root, "traceTime", latency_list_str);
    cJSON_AddItemToObject(cjson_ret, "testIndexData", root);

    free(dial_result);
    free(ip_list_str);
    free(latency_list_str);
}

static void _do_specify_dial_task(cJSON* cspeedTask, cJSON* cjson_result)
{
    cJSON* speedTactics = cJSON_GetObjectItem(cspeedTask, "speedTactics");
    cJSON* ptr = cJSON_GetObjectItem(cspeedTask, "indexType");
    cJSON* tactics = NULL;
    if (strcmp(ptr->valuestring, "ping") == 0) {
        tactics = cJSON_GetObjectItem(speedTactics, "pingTactics");
        log_trace("do specify ping task");
        _do_specify_ping(tactics, cjson_result);
    } else if (strcmp(ptr->valuestring, "traceroute") == 0) {
        tactics = cJSON_GetObjectItem(speedTactics, "tracerouteTactics");
        log_trace("do specify traceroute task");
        _do_specify_traceroute(tactics, cjson_result);
    } else if (strcmp(ptr->valuestring, "httpSpeed") == 0) {
        log_trace("do specify httpSpeed task");
        _do_specify_http_speed(speedTactics, cjson_result);
    }
    cJSON_AddStringToObject(cjson_result, "indexType", ptr->valuestring);
}
void* specify_dial_task(void* arg)
{
    char req_url[256] = { 0 };
    char *req_param = NULL, *push_req = NULL;
    cJSON *cresp = NULL, *cpush_resp = NULL, *creq_task = NULL,
          *cjson_result = NULL, *cptr = NULL, *cspeedTask = NULL;
    Platform_t* platform = (Platform_t*)arg;

    http_url(platform->addr.scheme, platform->addr.host, platform->addr.tcp_port,
        WEB_GET_SPEED_TACTICS_PATH, req_url);

    creq_task = cJSON_CreateObject();
    cJSON_AddStringToObject(creq_task, "probeId", commReqParam.probeId);
    cJSON_AddStringToObject(creq_task, "mac", commReqParam.mac);
    req_param = cJSON_Print(creq_task);
#if 1
    cresp = http_post(req_url, req_param);
#else
    char resp_str[] = "{\"speedTask\":{\"speedTaskId\":\"1\",\"indexType\":\"httpSpeed\",\"speedTactics\":{\"httpDownloadTactics\":{\"urls\":\"http://10.0.0.221:18081/nodeFile/test.bin,http://10.0.0.210:18081/nodeFile/test.bin,http://10.0.0.221:18081/nodeFile/test.bin,http://10.0.0.210:18081/nodeFile/test.bin\",\"downTime\":15,\"ignoreTime\":5,\"threads\":4,\"businessTag\":null},\"httpUploadTactics\":{\"urls\":\"http://10.0.0.221:18081/sts-base-node/servlet/upLoadData,http://10.0.0.210:18081/sts-base-node/servlet/upLoadData,http://10.0.0.221:18081/sts-base-node/servlet/upLoadData,http://10.0.0.210:18081/sts-base-node/servlet/upLoadData\",\"threads\":4,\"upTime\":15,\"ignoreTime\":5,\"businessTag\":null}}},\"status\":\"1\"}";
    cresp = cJSON_Parse(resp_str);
#endif
    if (!cresp) {
        log_trace("cresp is NULL, failed.");
        goto out;
    }

    if (!cJSON_IsObject(cresp)) {
        log_trace("resp is not json, failed.");
        goto out;
    }

    cptr = cJSON_GetObjectItem(cresp, "status");
    if (strcmp(cptr->valuestring, "1") != 0) {
        log_trace("status %s", cptr->valuestring);
        goto out;
    }

    cspeedTask = cJSON_GetObjectItem(cresp, "speedTask");

    cjson_result = cJSON_CreateObject();

    cptr = cJSON_GetObjectItem(cspeedTask, "speedTaskId");
    cJSON_AddStringToObject(cjson_result, "speedTaskId", cptr->valuestring);
    cJSON_AddStringToObject(cjson_result, "mac", commReqParam.mac);
    cJSON_AddStringToObject(cjson_result, "clientFactory", devInfo.factory);
    cJSON_AddStringToObject(cjson_result, "clientModel", devInfo.model);
    cJSON_AddStringToObject(cjson_result, "cityName", commReqParam.cityName);
    cJSON_AddStringToObject(cjson_result, "cityAlias", commReqParam.cityAlias);
    cJSON_AddStringToObject(cjson_result, "cityId", commReqParam.cityId);
    cJSON_AddStringToObject(cjson_result, "province", commReqParam.province);
    cJSON_AddStringToObject(cjson_result, "bdaccount", commReqParam.bdaccount);
    cJSON_AddStringToObject(cjson_result, "bdcode", commReqParam.bdcode);

    log_trace("do specify dial task.");
    _do_specify_dial_task(cspeedTask, cjson_result);

    http_url(platform->addr.scheme, platform->addr.host, platform->addr.tcp_port,
        WEB_PUSH_SPEED_DATA_PATH, req_url);
    push_req = cJSON_Print(cjson_result);
    cpush_resp = http_post(req_url, push_req);

out:
    if (creq_task)
        cJSON_Delete(creq_task);
    if (cresp)
        cJSON_Delete(cresp);
    if (cjson_result)
        cJSON_Delete(cjson_result);
    if (cpush_resp)
        cJSON_Delete(cpush_resp);
    if (req_param)
        free(req_param);
    if (push_req)
        free(push_req);
    return NULL;
}